package cn.ycl.system.biz.order.service.impl;

import cn.ycl.auth.api.user.domain.User;
import cn.ycl.auth.api.user.feign.RemoteUserService;
import cn.ycl.constans.Constants;
import cn.ycl.entity.UserInfoVO;
import cn.ycl.enums.OrderStatusEnum;
import cn.ycl.enums.OrderTypeEnum;
import cn.ycl.system.api.order.domain.KillOrder;
import cn.ycl.system.biz.delivery.dao.DeliveryAddressDao;
import cn.ycl.system.biz.delivery.entity.DeliveryAddress;
import cn.ycl.system.biz.order.dao.KillOrderDao;
import cn.ycl.system.biz.order.entity.KillOrderPageParam;
import cn.ycl.system.biz.order.entity.bo.KillOrderBO;
import cn.ycl.system.biz.order.entity.vo.KillOrderAndInfoVO;
import cn.ycl.system.biz.order.service.KillOrderService;
import cn.ycl.system.biz.product.dao.ProductDao;
import cn.ycl.system.biz.shop.dao.KillInfoDao;
import cn.ycl.system.biz.shop.entity.KillInfo;
import cn.ycl.system.biz.shop.service.KillInfoService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * (KillOrder)表服务实现类
 *
 * @author makejava
 * @since 2020-10-12 14:25:22
 */
@Service("killOrderService")
public class KillOrderServiceImpl implements KillOrderService {
    @Resource
    private KillOrderDao killOrderDao;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private KillInfoService killInfoService;
    @Resource
    private KillInfoDao killInfoDao;
    @Resource
    private DeliveryAddressDao deliveryAddressDao;
    @Resource
    private RemoteUserService remoteUserService;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public KillOrder queryById(Long id) {
        return this.killOrderDao.queryById(id);
    }

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit  查询条数
     * @return 对象列表
     */
    @Override
    public List<KillOrder> queryAllByLimit(int offset, int limit) {
        return this.killOrderDao.queryAllByLimit(offset, limit);
    }

    /**
     * 新增数据
     *
     * @param killOrder 实例对象
     * @return 实例对象
     */
    @Override
    public Integer insert(KillOrder killOrder) {
        return killOrderDao.insert(killOrder);
    }

    /**
     * 修改数据
     *
     * @param killOrder 实例对象
     * @return 实例对象
     */
    @Override
    public Integer update(KillOrder killOrder) {
        return killOrderDao.update(killOrder);
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Long id) {
        return this.killOrderDao.deleteById(id) > 0;
    }


    /**
     * 查询全部列表
     *
     * @return 是否成功
     */
    @Override
    public List<KillOrder> queryAll() {
        return killOrderDao.queryAll();
    }

    /**
     * 根据条件查询全部列表
     *
     * @param killOrder 查询条件
     * @return 是否成功
     */
    @Override
    public List<KillOrder> queryByOrder(KillOrder killOrder) {
        return killOrderDao.queryByOrder(killOrder);
    }


    /**
     * 优化的秒杀产品订单
     *
     * @param killOrderBO 订单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long secKillRedis(KillOrderBO killOrderBO) {
        //获取用户信息
        UserInfoVO userInfo = remoteUserService.getUserInfo();
        //判断是否已秒杀过
        List<KillOrder> killOrder1 = killOrderDao.getKillOrderByUserIdAndProductId(userInfo.getUserId(), killOrderBO.getProductId());
        if (killOrder1.size() > 0) {
            return killOrder1.get(0).getId();
        }
        //创建秒杀订单
        User user = killOrderBO.getUser();
        KillInfo killInfo = killInfoDao.getByProductId(killOrderBO.getProductId());
        KillOrder killOrder = new KillOrder();
        killOrder.setUserId(user.getUserId());
        killOrder.setProductId(killOrderBO.getProductId());
        killOrder.setConsignee(user.getUserName());
        killOrder.setPhone(user.getPhone());
        //1:秒杀   2：正常
        killOrder.setType(OrderTypeEnum.SECKILL_ORDER.getType());
        killOrder.setAmount(killInfo.getKillPrice());
        //1:创建   2：待支付  3：已支付  4：已接单   5：已完成
        killOrder.setStatus(OrderStatusEnum.CREAED.getType());
        killOrder.setOrderNo(String.valueOf(generateOrderId()));
        killOrder.setVersion(1);
        killOrder.setIsDeleted(false);
        killOrderDao.insert(killOrder);
        //扣减库存,可以防止超卖，因为在sql语句中已经加锁了，但是不友好
        int updateNum = killInfoDao.updateStock(killOrderBO.getProductId());
        if (updateNum <= 0) {
            throw new RuntimeException("商品已售完");
        }
        return killOrder.getId();
    }

    @Override
    public KillOrderAndInfoVO getKillOrder(Long orderId) {
        KillOrder killOrder = killOrderDao.getKillOrderByOrderId(orderId);
        DeliveryAddress deliveryAddress = null;
        KillOrderAndInfoVO killOrderAndInfoVO = new KillOrderAndInfoVO();
        if (!Objects.isNull(killOrder.getAddress())) {
            deliveryAddress = deliveryAddressDao.findByAddress(killOrder.getAddress());
            killOrderAndInfoVO.setDeliveryAddress(deliveryAddress);
        }
        Long productId = killOrder.getProductId();
        KillInfo killInfo = killInfoService.getByProductId(productId);

        killOrderAndInfoVO.setKillInfo(killInfo);
        killOrderAndInfoVO.setKillOrder(killOrder);
        return killOrderAndInfoVO;
    }

    @Override
    public void changeKillOrder(KillOrder killOrder) {
        killOrder.setStatus(OrderStatusEnum.HAD_PAY.getType());
        killOrder.setVersion(killOrder.getVersion() + 1);
        int update = killOrderDao.update(killOrder);
    }

    @Override
    public List<KillOrderBO> getKillOrderPage(KillOrderPageParam killOrderPageParam) {
        return killOrderDao.getKillOrderPage(killOrderPageParam);
    }

    @Override
    public Boolean checkUserAndOrder(Long orderId) {
        UserInfoVO userInfo = remoteUserService.getUserInfo();
        KillOrder killOrderByOrderId = killOrderDao.getKillOrderByOrderId(orderId);
        return userInfo.getUserId().equals(killOrderByOrderId.getUserId());
    }


    /**
     * PostConstruct只会在服务器加载servlet时执行一次
     * PostConstruct在构造函数之后执行，init（）方法之前执行
     */
    @PostConstruct
    public void initStock() {
        List<KillInfo> killInfos = killInfoService.queryAll();
        System.out.println("库存预热：\n");
        killInfos.forEach(killInfo -> {
            stringRedisTemplate.opsForValue().set(Constants.REDIS_PRODUCT_STOCK_PREFIX + killInfo.getProductId(), killInfo.getSku());
            System.out.println(killInfo.getName() + ":" + killInfo.getSku());
        });
    }

    /**
     * 获取年的后两位加上一年多少天+当前小时数作为前缀
     *
     * @param date
     * @return
     */
    public String getOrderIdPrefix(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        //补两位,因为一年最多三位数
        String monthFormat = String.format("%1$02d", month + 1);
        //补两位，因为日最多两位数
        String dayFormat = String.format("%1$02d", day);
        //补两位，因为小时最多两位数
        String hourFormat = String.format("%1$02d", hour);
        return year + monthFormat + dayFormat + hourFormat;
    }

    /**
     * 生成订单号orderNO
     *
     * @return
     */
    public Long generateOrderId() {
        String prefix = getOrderIdPrefix(new Date());
        String key = "KILL_ORDER_NO" + prefix;
        String orderId = null;
        try {
            Long increment = stringRedisTemplate.opsForValue().increment(key, 1);
            //往前补6位
            orderId = prefix + String.format("%1$06d", increment);
        } catch (Exception e) {
            throw new RuntimeException("生成订单号失败");
        }
        return Long.valueOf(orderId);
    }


}